﻿using System;
using System.Collections.Generic;
using System.Collections;
using Simp.CodeModel.CoreFunctions;

namespace Simp.CodeModel.CoreFunctions.Sequences
{
	/// <summary>Sequence of explicit elements.</summary>
	/// <remarks>The implementation holds the number of elements.  The elements themselves are passed in parameters.</remarks>
	public class ExplicitSequenceFunction : ISequenceFunction, IFunctionSerializer
	{
		#region Inner Types
		private class ExplicitSequenceAccessor : ISequenceAccessor
		{
			private readonly IFunction[] _elementList;

			public ExplicitSequenceAccessor(IFunction[] elementList)
			{
				_elementList = elementList;
			}

			#region ISequenceAccessor Members
			int ISequenceAccessor.Count
			{
				get { return _elementList.Length; }
			}

			IFunction ISequenceAccessor.this[int index]
			{
				get { return _elementList[index]; }
			}
			#endregion

			#region IEnumerable<IFunction> Members
			IEnumerator<IFunction> IEnumerable<IFunction>.GetEnumerator()
			{
				foreach (IFunction function in _elementList)
				{
					yield return function;
				}
			}
			#endregion

			#region IEnumerable Members
			IEnumerator IEnumerable.GetEnumerator()
			{
				return _elementList.GetEnumerator();
			}
			#endregion
		}
		#endregion

		/// <summary>Name of the function.</summary>
		public const string ExplicitSequenceFunctionName = "ExplicitSequence";

		private readonly string[] _parameterList;

		/// <summary>Construct a sequence with its lenght (the elements are function parameters).</summary>
		/// <param name="count"></param>
		public ExplicitSequenceFunction(int count)
		{
			if (count < 0)
			{
				throw new ArgumentException("Must be greater or equal to zero", "count");
			}

			_parameterList = new string[count];

			for (int i = 0; i != count; ++i)
			{
				_parameterList[i] = string.Concat("element", (i + 1).ToString());
			}
		}

		#region IFunction Members
		string IFunction.FunctionName
		{
			get { return ExplicitSequenceFunctionName; }
		}

		string[] IFunction.ParameterNames
		{
			get { return _parameterList; }
		}

		IFunctionParameterBinding[] IFunction.DefaultParameterValues
		{
			get { return FunctionHelper.EmptyBindings; }
		}

		IFunction IFunction.Simplify(SimplificationMode simplificationMode, params IFunction[] parameters)
		{
			return null;
		}

		IFunction IFunction.AcceptVisitor(IFunctionVisitor visitor)
		{
			return null;
		}
		#endregion

		#region ISequenceFunction Members
		ISequenceAccessor ISequenceFunction.GetAccessor(params IFunction[] parameters)
		{
			FunctionHelper.ValidateParameters(this, parameters);

			return new ExplicitSequenceAccessor(parameters);
		}
		#endregion

		#region IFunctionSerializer Members
		void IFunctionSerializer.Serialize(AppendOnlyStringBuilder builder, params IFunction[] parameters)
		{
			FunctionHelper.ValidateParameters(this, parameters);

			if (builder == null)
			{
				throw new ArgumentNullException("builder");
			}
	
			builder.Append("{");
			for (int i = 0; i != parameters.Length; ++i)
			{
				IFunction function = parameters[i];

				FunctionHelper.Serialize(function, builder);
				if (i != parameters.Length - 1)
				{
					builder.Append(", ");
				}
			}
			builder.Append("}");
		}
		#endregion

		/// <summary>Returns the number of element supported by this sequence.</summary>
		public int Count
		{
			get { return _parameterList.Length; }
		}
	}
}